﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ANTLRTest.Context
{
    public class ContextWalker
    {
        #region Constructor

        public ContextWalker(Type parserType, Type lexerType)
        {
            if (parserType == null) throw new ArgumentNullException("parserType");
            if (lexerType == null) throw new ArgumentNullException("lexerType");

            if (parserType.BaseType != typeof(Antlr.Runtime.Parser) && parserType != typeof(Antlr.Runtime.Parser)) throw new ArgumentException("parserType must be inherited from Antlr.Runtime.Parser", "parserType");
            if (lexerType.BaseType != typeof(Antlr.Runtime.Lexer) && lexerType != typeof(Antlr.Runtime.Lexer)) throw new ArgumentException("lexerType must be inherited from Antlr.Runtime.Lexer", "lexerType");
            
            this.ParserType = parserType;
            this.LexerType = lexerType;

            this.parserTokenNames = new List<string>();
            FieldInfo tokenNamesFI = parserType.GetField("tokenNames");
            if (tokenNamesFI == null) throw new ArgumentException("parserType has no tokenNames field", "parserType");
            object tokenNamesValue = tokenNamesFI.GetValue(null);

            if (tokenNamesValue is string[])
            {
                foreach (var item in tokenNamesValue as string[])
                    this.parserTokenNames.Add(item);
            }

            MethodBody body = parserType.GetMethod("program").GetMethodBody();
            var sssss = body.ExceptionHandlingClauses;


            var mis = parserType.GetFields().Where(
                mi => mi.Name.StartsWith("FOLLOW_") && mi.Name.Contains("_in_")).Select(
                    mi => CreateFollowPresenter(mi)).ToList();

            foreach (var item in mis)
            {

            }
        }

        #endregion

        #region Public methods

        public ContextSequence GetSequence(string baseText,string baseRule)
        {
            ContextSequence sequence = new ContextSequence(this, baseText, baseRule);
            return sequence;
        }

        public string GetTokenName(int tokenType)
        { 
            string result = null;
            
            if (tokenType < parserTokenNames.Count && tokenType >= 0)
            {
                result = parserTokenNames[tokenType];
            }

            return result;
        }

        #endregion

        #region Private methods

        private FollowPresenter CreateFollowPresenter(FieldInfo memberInfo)
        {
            string member = memberInfo.Name;
            Antlr.Runtime.BitSet bs = memberInfo.GetValue(null) as Antlr.Runtime.BitSet;
            var resultTokens = bs.ToArray().Select(tt => this.GetTokenName(tt)).ToList();

            member = member.Substring("FOLLOW_".Length);
            int indexOfIn = member.IndexOf("_in_");
            string value = member.Substring(indexOfIn + "_in_".Length);
            int valueIntegerSufixIndex = value.IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
            if (valueIntegerSufixIndex != -1)
            {
                value = value.Substring(0, valueIntegerSufixIndex);
            }
            string key = member.Substring(0, indexOfIn);
            int tokenType = 0;
            if (Int32.TryParse(key, out tokenType))
            {
                key = this.GetTokenName(tokenType);
            }
            FollowPresenter result = new FollowPresenter(key, value, resultTokens);
            return result;
        }

        #endregion

        #region Properties

        public Type ParserType { get; private set; }
        public Type LexerType { get; private set; }

        #endregion

        private List<string> parserTokenNames;
    }
}
